<template>
  <div class="one2one0meeting">
    <div class="title m-b-20 p-10">
      <div>
        <span>会议号：{{ roomId }}</span>
        <el-button
          @click="onCopy"
          :data-clipboard-text="copyValue"
          class="m-l-20 copy"
          type="success"
        >
          复制链接
        </el-button>
        <el-button :disabled="isShareScreen || remoteStream === null" @click="onOpenScreenShare">
          共享屏幕
        </el-button>
      </div>
      <Device :device-can-select="deviceCanSelect" @switchDevice="switchDevice" />
      <el-button @click="onLeaveBtnClick" type="primary">离开</el-button>
    </div>
    <div class="videos">
      <div
        @mouseenter="localVideoMouseEnter(true)"
        @mouseleave="localVideoMouseEnter(false)"
        class="local-video"
      >
        <video
          :muted="!isShowRemote"
          controls
          width="900"
          height="600"
          id="localVideo"
          autoplay
          playsinline
        ></video>
        <span class="username">用户：{{ isShowRemote ? remoteNickName : localNickName }}</span>
        <div v-if="localStream && !isShowRemote && isLocalVideoEnter && !isShareScreen">
          <img
            v-if="isVideoOpen"
            @click="onVideoCloseBtn"
            class="video-btn"
            src="@/assets/images/video.png"
          />
          <img
            v-if="!isVideoOpen"
            @click="onVideoOpenBtn"
            class="video-btn"
            src="@/assets/images/video_close.png"
          />
          <img
            v-if="isAudioOpen"
            @click="onAudioCloseBtn"
            class="audio-btn"
            src="@/assets/images/audio.png"
          />
          <img
            v-if="!isAudioOpen"
            @click="onAudioOpenBtn"
            class="audio-btn"
            src="@/assets/images/audio_close.png"
          />
        </div>
      </div>
      <div class="right">
        <div
          @mouseenter="remoteVideoMouseEnter(true)"
          @mouseleave="remoteVideoMouseEnter(false)"
          class="remote-video"
        >
          <div v-if="!remoteStream" class="mask">用户未进入</div>
          <div v-else class="change-to-main-screen">单击切换到主屏</div>
          <video
            v-show="remoteStream"
            width="321"
            height="214"
            id="remoteVideo"
            autoplay
            @click="onRemoteWindowClick"
            :muted="isShowRemote"
          ></video>
          <span v-if="remoteStream" class="username">
            用户：{{ isShowRemote ? localNickName : remoteNickName }}
          </span>
          <div v-if="remoteStream && isShowRemote && isRemoteVideoEnter && !isShareScreen">
            <img
              v-if="isVideoOpen"
              @click="onVideoCloseBtn"
              class="video-btn"
              src="@/assets/images/video.png"
            />
            <img
              v-if="!isVideoOpen"
              @click="onVideoOpenBtn"
              class="video-btn"
              src="@/assets/images/video_close.png"
            />
            <img
              v-if="isAudioOpen"
              @click="onAudioCloseBtn"
              class="audio-btn"
              src="@/assets/images/audio.png"
            />
            <img
              v-if="!isAudioOpen"
              @click="onAudioOpenBtn"
              class="audio-btn"
              src="@/assets/images/audio_close.png"
            />
          </div>
        </div>
        <div class="chat">
          <div class="chat-title">聊天框</div>
          <div ref="scrollBar" class="chat-content-box">
            <div ref="chatBox" class="chat-content">
              <div v-for="(chat, index) in chatList" :key="index">
                {{ `${'用户' + chat.remoteNickName}说：${chat.msg}` }}
              </div>
            </div>
          </div>
          <div class="chat-bottom">
            <el-input
              @keyup.enter.native="onSendMsg"
              v-model="content"
              placeholder="输入内容"
              clearable
            />
            <el-button @click="onSendMsg" type="primary">发送</el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import type { Chat } from './type';
import Clipboard from 'clipboard';
import { createRoom, reqIsMeetingExist } from '@/api/video';
import { getLoginUserId, getToken } from '@/utils/storage';
import { useWebsocketStore } from '@/store/websocket';
import {
  SIGNAL_TYPE_JOIN,
  SIGNAL_TYPE_RESP_JOIN,
  SIGNAL_TYPE_LEAVE,
  SIGNAL_TYPE_NEW_PEER,
  SIGNAL_TYPE_PEER_LEAVE,
  SIGNAL_TYPE_OFFER,
  SIGNAL_TYPE_ANSWER,
  SIGNAL_TYPE_CANDIDATE,
  SIGNAL_TYPE_CHAT,
  SIGNAL_TYPE_MUT_ROOM_CHAT,
} from '@/constants/constants';
import Device from '@/components/Device/index.vue';
import appStore from '@/store';
import { parseStringToObject } from '@/utils/parse';
import { useUserStore } from '@/store/user';

const userStore = useUserStore();

const localUserId = ref<string>(getLoginUserId() + ''); // 本地uid
const localNickName = ref<string>(userStore.userInfo.userMsg.nickName);
const remoteUserId = ref<string>(''); // 对端
const remoteNickName = ref<string>('');
let roomId = ref<string>('');

let localVideo: HTMLVideoElement;
let remoteVideo: HTMLVideoElement;
let localStream = ref<MediaStream>();
let remoteStream = ref<MediaStream | null>(null);
let pc: RTCPeerConnection | null = null;
let zeroRTCEngine: ZeroRTCEngine;

let videoTrack: MediaStreamTrack;
let screenTrack: MediaStreamTrack;
const store = appStore();

// 开启/关闭屏幕共享
const isShareScreen = ref<boolean>(false);
const onOpenScreenShare = () => {
  if (isShareScreen.value) return;
  navigator.mediaDevices
    .getDisplayMedia({
      video: {
        width: { ideal: 1920 },
        height: { ideal: 1080 },
        frameRate: { ideal: 30, max: 60 },
      },
    })
    .then((screenStream) => {
      isShareScreen.value = true;
      videoTrack = localStream.value?.getVideoTracks()[0]!;
      localStream.value?.removeTrack(videoTrack!);
      screenTrack = screenStream.getTracks()[0];
      localStream.value!.addTrack(screenTrack);
      // localVideo.srcObject = localStream.value!;
      // 将新的视频轨道替换到 PeerConnection 中
      if (pc) {
        const sender = pc.getSenders().find((sender) => sender.track === videoTrack);
        sender!.replaceTrack(screenTrack);
      }
      // videoTrack?.stop();
      screenTrack.onended = () => {
        onCloseScreenShare();
      };
    })
    .catch(() => {});
};
const onCloseScreenShare = () => {
  isShareScreen.value = false;
  localStream.value?.removeTrack(screenTrack!);
  localStream.value!.addTrack(videoTrack);
  // 将摄像头视频轨道替换到 PeerConnection 中
  if (pc) {
    const sender = pc.getSenders().find((sender) => sender.track === screenTrack);
    sender!.replaceTrack(videoTrack);
  }
  // localVideo.srcObject = localStream.value!;
  screenTrack?.stop();
};

const isJoin = ref(false);
let hasNewZeroRTCEngine = false;
// 选择音视频设备的回调
async function switchDevice({ videoId, audioId }: { videoId: string; audioId: string }) {
  if (videoId && audioId && !isJoin.value) {
    if (!hasNewZeroRTCEngine) {
      zeroRTCEngine = new ZeroRTCEngine('wss://ly.guilinsx.com:9090/OnlineVideo/ws');
      zeroRTCEngine.createWebsocket();
      hasNewZeroRTCEngine = true;
    } else {
      zeroRTCEngine.initLocalStream();
    }
    return;
  } else {
    // 切换音频或视频时重新更新音视频
    zeroRTCEngine?.initLocalStream();
  }
}

// 控制视频/音频按钮的显示
const isLocalVideoEnter = ref<boolean>(false);
const localVideoMouseEnter = (isEnter: boolean) => {
  isLocalVideoEnter.value = isEnter;
};
const isRemoteVideoEnter = ref<boolean>(false);
const remoteVideoMouseEnter = (isEnter: boolean) => {
  isRemoteVideoEnter.value = isEnter;
};

// 在线聊天
const content = ref<string>('');
const chatList = reactive<Array<any>>([]);
const onSendMsg = () => {
  if (!store.isJoined) {
    ElMessage({
      message: '请先选择视频/音频设备',
      type: 'warning',
    });
    return;
  }
  const msg = content.value.trim();
  if (!msg) {
    ElMessage({
      message: '请输入内容！',
      type: 'warning',
    });
  } else {
    const transferData: Chat = {
      cmd: SIGNAL_TYPE_CHAT,
      roomId: roomId.value,
      // uid: localUserId.value,
      remoteUid: remoteUserId.value,
      msg: content.value,
    };
    websocketStore.sendMessage(JSON.stringify(transferData));
  }
  content.value = '';
};

function handleChat(msgObject: Chat) {
  chatList.push(msgObject);
  updateScrollTop();
}

// 控制聊天滚动条
const chatBox = ref();
const scrollBar = ref();
function updateScrollTop() {
  // 更新滚动高度
  const chatBoxHeight = chatBox.value?.scrollHeight;
  scrollBar.value.scrollTop = chatBoxHeight;
  // 等待DOM重新渲染，再次更新滚动高度
  nextTick(() => {
    const chatBoxHeight = chatBox.value?.scrollHeight;
    scrollBar.value.scrollTop = chatBoxHeight;
  });
}

// 初始化
const route = useRoute();
const router = useRouter();
const deviceCanSelect = ref(true);
onMounted(async () => {
  localVideo = document.querySelector('#localVideo') as HTMLVideoElement;
  remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement;
  if (typeof route.query.meetingNo === 'string') {
    roomId.value = route.query.meetingNo;
  }
  if (!roomId.value) {
    const res: any = await createRoom({
      type: 'double',
    });
    if (res?.code === 200) {
      ElMessageBox.alert('点击上方选择视频/音频设备后才会加入会议', '提示');
      roomId.value = res.data.roomId;
      // 添加路由参数
      router.replace({
        path: route.path,
        query: {
          meetingNo: roomId.value,
        },
      });
    }
  } else {
    // 如果路由携带了会议id，则需要判断该会议号是否存在
    reqIsMeetingExist(roomId.value).then((res: any) => {
      if (res.code !== 200) {
        deviceCanSelect.value = false;
        ElMessageBox.confirm('会议号不存在或会议已结束', '提示', {
          confirmButtonText: '确定',
          type: 'error',
        })
          .then(() => {})
          .catch(() => {});
      } else {
        ElMessageBox.alert('点击上方选择视频/音频设备后才会加入会议', '提示');
      }
    });
  }

  // // 初始化本地码流
  // // zeroRTCEngine = new ZeroRTCEngine('ws://114.132.229.194:10000');
  // zeroRTCEngine = new ZeroRTCEngine('ws://localhost:8080/OnlineVideo/ws');
  // // zeroRTCEngine = new ZeroRTCEngine("wss://129.211.184.235:8089/ws");
  // zeroRTCEngine.createWebsocket();
});

// 复制会议链接
const copyValue = computed(() => {
  return `https://ly.guilinsx.com:9090/#/single-meeting?meetingNo=${roomId.value}`;
});
const onCopy = () => {
  const clipboard = new Clipboard('.copy');
  clipboard.on('success', (e) => {
    ElMessage({
      message: '复制成功',
      type: 'success',
    });
    // 释放内存
    clipboard.destroy();
  });
  clipboard.on('error', (e) => {
    // 不支持复制
    ElMessage({
      message: '复制失败，你的浏览器不支持通过该方式进行复制！',
      type: 'success',
    });
    // 释放内存
    clipboard.destroy();
  });
};

const onLeaveBtnClick = () => {
  ElMessageBox.confirm('确定离开当前房间吗，若离开，将关闭当前标签页！', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
  })
    .then(() => {
      doLeave();
      window.close();
    })
    .catch(() => {});
};

// 开启/关闭摄像头
const isVideoOpen = ref<boolean>(true);
const onVideoCloseBtn = () => {
  // 调用stop是永久性的，修改enabled则是暂时的
  // localStream?.getVideoTracks()[0].stop();
  localStream.value!.getVideoTracks()[0].enabled = false;
  isVideoOpen.value = false;
};
const onVideoOpenBtn = () => {
  localStream.value!.getVideoTracks()[0].enabled = true;
  if (isShowRemote.value) {
    remoteVideo.srcObject = localStream.value!;
  } else {
    localVideo.srcObject = localStream.value!;
  }
  isVideoOpen.value = true;
};
// 开启/关闭音频
const isAudioOpen = ref<boolean>(true);
const onAudioCloseBtn = () => {
  localStream.value!.getAudioTracks()[0].enabled = false;
  isAudioOpen.value = false;
};
const onAudioOpenBtn = () => {
  localStream.value!.getAudioTracks()[0].enabled = true;
  isAudioOpen.value = true;
};

const isShowRemote = ref<boolean>(false);
const onRemoteWindowClick = () => {
  if (isShowRemote.value) {
    isShowRemote.value = false;
    localVideo.srcObject = localStream.value!;
    remoteVideo.srcObject = remoteStream.value!;
  } else {
    isShowRemote.value = true;
    localVideo.srcObject = remoteStream.value!;
    remoteVideo.srcObject = localStream.value!;
  }
};

function handleIceCandidate(event: RTCPeerConnectionIceEvent) {
  console.info('handleIceCandidate', event.candidate);
  if (event.candidate) {
    const candidateJson = {
      label: event.candidate.sdpMLineIndex,
      id: event.candidate.sdpMid,
      candidate: event.candidate.candidate,
    };
    const jsonMsg = {
      cmd: SIGNAL_TYPE_CANDIDATE,
      roomId: roomId.value,
      uid: localUserId.value,
      remoteUid: remoteUserId.value,
      msg: JSON.stringify(candidateJson),
    };
    const message = JSON.stringify(jsonMsg);
    zeroRTCEngine.sendMessage(message);
    console.info('handleIceCandidate message: ' + message);
    console.info('send candidate message');
  } else {
    console.warn('End of candidates');
  }
}

function handleRemoteStreamAdd(event: RTCTrackEvent) {
  console.info('handleRemoteStreamAdd');
  remoteStream.value = event.streams[0];
  remoteVideo.srcObject = remoteStream.value;
}

function handleConnectionStateChange() {
  if (pc != null) {
    console.info('ConnectionState -> ' + pc.connectionState);
  }
}

function handleIceConnectionStateChange() {
  if (pc != null) {
    console.info('IceConnectionState -> ' + pc.iceConnectionState);
  }
}

function createPeerConnection() {
  const defaultConfiguration: RTCConfiguration = {
    bundlePolicy: 'max-bundle',
    rtcpMuxPolicy: 'require',
    iceTransportPolicy: 'all', //relay 或者 all
    // 修改ice数组测试效果，需要进行封装
    iceServers: [
      // {
      //   urls: [
      //     'turn:192.168.17.129:3478?transport=udp',
      //     'turn:192.168.17.129:3478?transport=tcp', // 可以插入多个进行备选
      //   ],
      //   username: 'admin',
      //   credential: '123456',
      // },
      // {
      //   urls: ['stun:192.168.17.129:3478'],
      // },
      {
        urls: [
          'turn:114.132.229.194:3478?transport=udp',
          'turn:114.132.229.194:3478?transport=tcp', // 可以插入多个进行备选
        ],
        username: 'admin',
        credential: '123456',
      },
      {
        urls: ['stun:114.132.229.194:3478'],
      },
    ],
  };

  pc = new RTCPeerConnection(defaultConfiguration); // 音视频通话的核心类
  pc.onicecandidate = handleIceCandidate;
  pc.ontrack = handleRemoteStreamAdd;
  pc.onconnectionstatechange = handleConnectionStateChange;
  pc.oniceconnectionstatechange = handleIceConnectionStateChange;
  if (localStream.value) {
    localStream.value.getTracks().forEach((track) => pc!.addTrack(track, localStream.value!)); // 把本地流设置给RTCPeerConnection
  }
}

function createOfferAndSendMessage(session: RTCSessionDescriptionInit) {
  pc &&
    pc
      .setLocalDescription(session)
      .then(function () {
        const jsonMsg = {
          cmd: SIGNAL_TYPE_OFFER,
          roomId: roomId.value,
          uid: localUserId.value,
          remoteUid: remoteUserId.value,
          msg: JSON.stringify(session),
        };
        const message = JSON.stringify(jsonMsg);
        zeroRTCEngine.sendMessage(message);
        // console.info("send offer message: " + message);
        console.info('send offer message');
      })
      .catch(function (error) {
        console.error('offer setLocalDescription failed: ' + error);
      });
}

function handleCreateOfferError(error: any) {
  console.error('handleCreateOfferError: ' + error);
}

function createAnswerAndSendMessage(session: RTCSessionDescriptionInit) {
  console.log('=======================');

  pc &&
    pc
      .setLocalDescription(session)
      .then(function () {
        const jsonMsg = {
          cmd: SIGNAL_TYPE_ANSWER,
          roomId: roomId.value,
          uid: localUserId.value,
          remoteUid: remoteUserId.value,
          msg: JSON.stringify(session),
        };
        const message = JSON.stringify(jsonMsg);
        zeroRTCEngine.sendMessage(message);
        // console.info("send answer message: " + message);
        console.info('send answer message');
      })
      .catch(function (error) {
        console.error('answer setLocalDescription failed: ' + error);
      });
}

function handleCreateAnswerError(error: any) {
  console.error('handleCreateAnswerError: ' + error);
}

const websocketStore = useWebsocketStore();

class ZeroRTCEngine {
  wsUrl: string;
  signaling: WebSocket;

  constructor(wsUrl: string) {
    const token = getToken();
    this.wsUrl = `${wsUrl}?token=${token}`;
    // this.signaling = new WebSocket(this.wsUrl);
    this.signaling = websocketStore.connect();
  }

  createWebsocket() {
    this.initLocalStream();
    // this.signaling.onopen = () => {
    //   console.log('websocket open');
    //   this.initLocalStream();
    // };
    this.signaling.addEventListener('message', (event) => {
      let jsonMsg = parseStringToObject(event.data);
      console.log('receive message from server：', jsonMsg);
      switch (jsonMsg.cmd) {
        case SIGNAL_TYPE_NEW_PEER:
          handleRemoteNewPeer(jsonMsg);
          break;
        case SIGNAL_TYPE_RESP_JOIN:
          handleResponseJoin(jsonMsg);
          break;
        case SIGNAL_TYPE_PEER_LEAVE:
          handleRemotePeerLeave(jsonMsg);
          break;
        case SIGNAL_TYPE_OFFER:
          handleRemoteOffer(jsonMsg);
          break;
        case SIGNAL_TYPE_ANSWER:
          handleRemoteAnswer(jsonMsg);
          break;
        case SIGNAL_TYPE_CANDIDATE:
          handleRemoteCandidate(jsonMsg);
          break;
        case SIGNAL_TYPE_MUT_ROOM_CHAT:
          handleChat(jsonMsg);
      }
    });
    this.signaling.onerror = (event) => {
      console.log('onError: ' + event);
    };
    this.signaling.onclose = (event) => {
      console.log('onClose -> code: ' + event.code + ', reason:' + event.reason);
    };
  }
  sendMessage(message: string) {
    // this.signaling.send(message);
    // 使用下面的方法进行发送消息，可判断连接状态
    websocketStore.sendMessage(message);
  }
  initLocalStream() {
    const videoId = store.videoDeviceId;
    const audioId = store.audioDeviceId;
    const constraints: MediaStreamConstraints = {
      audio: true,
      video: {
        width: { ideal: 1280 },
        height: { ideal: 720 },
      },
    };
    if (videoId) {
      constraints.video = {
        width: { ideal: 1280 },
        height: { ideal: 720 },
        deviceId: { exact: videoId },
      };
    }
    if (audioId) {
      constraints.audio = {
        deviceId: { exact: audioId },
      };
    }
    console.log('constraints', constraints);

    navigator.mediaDevices
      .getUserMedia(constraints)
      .then(openLocalStream)
      .catch(function (e) {
        console.log('getUserMedia() error: ' + e);
        ElMessage({
          message: '选择的音视频设备已被占用，请选择其他设备！',
          type: 'error',
        });
      });
  }
}

function handleResponseJoin(message: any) {
  console.info('handleResponseJoin, remoteUid: ' + message.remoteUid);
  remoteUserId.value = message.remoteUid;
  remoteNickName.value = message.remoteNickName;
  // doOffer();
}

function handleRemotePeerLeave(message: any) {
  console.info('handleRemotePeerLeave, remoteUid: ', message);
  ElMessage({
    message: `用户${message.remoteNickName}离开房间！`,
    type: 'warning',
  });
  // 如果主屏展示的是对方的视频，则需要将小屏展示在主屏中
  if (isShowRemote.value) {
    isShowRemote.value = false;
    localVideo.srcObject = localStream.value!;
  }
  remoteVideo.srcObject = null;
  remoteStream.value = null;
  // 对方离开房间时，不需要关闭pc
  // if (pc != null) {
  //   pc.close();
  //   pc = null;
  // }
}

function handleRemoteNewPeer(message: any) {
  console.info('handleRemoteNewPeer=================: ', message);
  ElMessage({
    message: `用户${message.remoteNickName}加入房间！`,
    type: 'success',
  });
  remoteUserId.value = message.remoteUid;
  remoteNickName.value = message.remoteNickName;
  doOffer();
}

function handleRemoteOffer(message: any) {
  console.info('handleRemoteOffer');
  if (pc == null) {
    createPeerConnection();
  }
  const desc = JSON.parse(message.msg);
  pc && pc.setRemoteDescription(desc);
  doAnswer();
}

function handleRemoteAnswer(message: any) {
  console.info('handleRemoteAnswer');
  const desc = JSON.parse(message.msg);
  pc && pc.setRemoteDescription(desc);
}

function handleRemoteCandidate(message: any) {
  console.info('handleRemoteCandidate');
  const jsonMsg = JSON.parse(message.msg);
  const candidateMsg = {
    sdpMLineIndex: jsonMsg.label,
    sdpMid: jsonMsg.id,
    candidate: jsonMsg.candidate,
  };
  const candidate = new RTCIceCandidate(candidateMsg);
  pc &&
    pc.addIceCandidate(candidate).catch((e) => {
      console.error('addIceCandidate failed:' + e.name);
    });
}

function doOffer() {
  // 创建RTCPeerConnection
  if (pc == null) {
    createPeerConnection();
  }
  pc && pc.createOffer().then(createOfferAndSendMessage).catch(handleCreateOfferError);
}

function doAnswer() {
  pc && pc.createAnswer().then(createAnswerAndSendMessage).catch(handleCreateAnswerError);
}

function doJoin(roomId: string) {
  const jsonMsg = {
    cmd: SIGNAL_TYPE_JOIN,
    roomId: roomId,
    // uid: localUserId.value,
  };
  const message = JSON.stringify(jsonMsg);
  zeroRTCEngine.sendMessage(message);
  console.info('doJoin message: ' + message);
}

function doLeave() {
  const jsonMsg = {
    cmd: SIGNAL_TYPE_LEAVE,
    roomId: roomId.value,
    uid: localUserId.value,
  };
  const message = JSON.stringify(jsonMsg);
  zeroRTCEngine.sendMessage(message);
  console.info('doLeave message: ' + message);
  hangup();
}

function hangup() {
  localVideo.srcObject = null; // 0.关闭自己的本地显示
  remoteVideo.srcObject = null; // 1.不显示对方
  closeLocalStream(); // 2. 关闭本地流
  if (pc != null) {
    pc.close(); // 3.关闭RTCPeerConnection
    pc = null;
  }
}

function closeLocalStream() {
  if (localStream.value) {
    localStream.value.getTracks().forEach((track) => {
      track.stop();
    });
  }
}

function openLocalStream(stream: MediaStream) {
  console.log('Open local stream');
  // 已加入过房间时，此时需要做的是更新音视频轨道
  if (isJoin.value) {
    // 更新视频轨道
    videoTrack = localStream.value?.getVideoTracks()[0]!;
    localStream.value?.removeTrack(videoTrack);
    const newVideoTrack = stream.getVideoTracks()[0];
    localStream.value?.addTrack(newVideoTrack);
    if (pc) {
      const sender = pc.getSenders().find((sender) => sender.track === videoTrack);
      sender!.replaceTrack(newVideoTrack);
    }
    // 更新音频轨道
    const audioTrack = localStream.value?.getAudioTracks()[0]!;
    localStream.value?.removeTrack(audioTrack);
    const newAudioTrack = stream.getAudioTracks()[0];
    localStream.value?.addTrack(newAudioTrack);
    if (pc) {
      const sender = pc.getSenders().find((sender) => sender.track === audioTrack);
      sender!.replaceTrack(newAudioTrack);
    }
    // 切换音视频后，如果原来是静音，则切换后也静音
    if (!isAudioOpen.value) {
      localStream.value!.getAudioTracks()[0].enabled = false;
    }
    if (!isVideoOpen.value) {
      localStream.value!.getVideoTracks()[0].enabled = false;
    }
  }
  // 如果还未加入过，才加入房间
  if (!isJoin.value) {
    doJoin(roomId.value);
    isJoin.value = true;
    store.isJoined = true;
    localVideo.srcObject = stream; // 显示画面
    localStream.value = stream; // 保存本地流的句柄
  }
}
</script>

<style lang="scss" scoped>
.one2one0meeting {
  .title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #fff;
  }
  .videos {
    display: flex;
    justify-content: space-between;
    .local-video,
    .remote-video {
      position: relative;
      .username {
        position: absolute;
        top: 0px;
        left: 0px;
        padding: 5px;
        color: white;
        background-color: rgba(0, 0, 0, 0.5);
        border-bottom-right-radius: 5px;
      }
      .video-btn,
      .audio-btn {
        position: absolute;
        top: 20px;
        right: 20px;
        width: 40px;
        height: 40px;
        background-color: #f0f0f0;
        border-radius: 5px;
      }
      .video-btn {
        right: 80px;
      }
    }
    video {
      vertical-align: bottom;
      background-color: black;
      border-radius: 5px;
    }
    .remote-video {
      width: 321px;
      height: 214px;
      background-color: #e6e6e9;
      .mask {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .change-to-main-screen {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        color: #fff;
        z-index: 9;
        display: none;
      }
      &:hover .change-to-main-screen {
        display: inline-block;
      }
      .video-btn,
      .audio-btn {
        top: 10px;
        right: 10px;
        width: 20px;
        height: 20px;
      }
      .video-btn {
        right: 40px;
      }
      video {
        cursor: pointer;
        &:hover {
          border: 2px solid rgba(0, 0, 0, 0.658);
        }
      }
    }
    .right {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      .chat {
        display: flex;
        flex-direction: column;
        width: 320px;
        height: 370px;
        border: 2px solid #d9dade81;
        &-title {
          padding: 5px 10px;
          flex-shrink: 0;
          background-color: #d9dade81;
        }
        &-content-box {
          flex: 1;
          background-color: #fff;
          padding: 10px;
          overflow-y: auto;

          .content {
            flex: 1;
          }
        }
        &-bottom {
          flex-shrink: 0;
          height: 32px;
          width: 100%;
          display: flex;
          align-items: center;
        }
      }
    }
  }
}
/* 隐藏时间控件 */
video::-webkit-media-controls-timeline {
  display: none !important;
}

video::-moz-range-thumb {
  display: none !important;
}

video::-ms-thumb {
  display: none !important;
}
</style>
